/*
 * @Description: websocket封装
 * @Author: huacong
 * @Date: 2020-07-08 15:08:48
 * @LastEditTime: 2020-08-26 15:00:37
 * @LastEditors: huacong
 */
import Vue from 'vue'
const websocks = {}

// 初始化weosocket
function initWebSocket ({ ws, data, msgCallback, closeCallback }) {
  if (!window.WebSocket) {
    Vue.prototype.$message.warning('当前浏览器不支持WebSocket')
    return
  }

  let lockReconnect = false // 避免ws重复连接
  let websock = null

  const createSocket = () => {
    // ws地址 -->这里是你的请求路径
    websocks[ws] = new WebSocket(ws)
    websock = websocks[ws]
  }

  createSocket()
  websock.onmessage = function (e) {
    console.log('on message' + e.data)
    heartCheck.reset().start(websock) // 拿到任何消息都说明当前连接是正常的
    if (e.data !== 'ping') {
      if (msgCallback) msgCallback(JSON.parse(e.data))
    }
  }

  websock.onopen = function () { // 绑定连接事件
    console.log('Connection open ...')
    websock.send(JSON.stringify(data))
    heartCheck.reset().start(websock) // 心跳检测重置
  }
  websock.onclose = function (e) { // 绑定关闭或断开连接事件
    console.log('Connection closed.', e)
    reconnect(ws, data, msgCallback, closeCallback)
  }

  // 连接发生错误的回调方法
  websock.onerror = function (evt) {
    console.log('WebSocket连接发生错误', evt)
    reconnect(ws, data, msgCallback, closeCallback)
  }

  const reconnect = () => {
    if (lockReconnect) return
    lockReconnect = true
    setTimeout(function () { // 没连接上会一直重连，设置延迟避免请求过多
      createSocket()
      lockReconnect = false
    }, 2000)
  }

  // 心跳检测
  const heartCheck = {
    timeout: 1000, // 1分钟发一次心跳
    timeoutObj: null,
    serverTimeoutObj: null,
    reset: function () {
      clearTimeout(this.timeoutObj)
      clearTimeout(this.serverTimeoutObj)
      return this
    },
    start: function (ws) {
      const self = this
      this.timeoutObj = setTimeout(function () {
        // 这里发送一个心跳，后端收到后，返回一个心跳消息，
        // onmessage拿到返回的心跳就说明连接正常
        ws.send('ping')
        self.serverTimeoutObj = setTimeout(function () { // 如果超过一定时间还没重置，说明后端主动断开了
          ws.close() // 如果onclose会执行reconnect，我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
        }, self.timeout)
      }, this.timeout)
    }
  }

  return websocks[ws]
}

export default initWebSocket
